package com.atguigu.exam.service.impl;


import com.atguigu.exam.entity.ExamRecord;
import com.atguigu.exam.entity.Paper;
import com.atguigu.exam.entity.PaperQuestion;
import com.atguigu.exam.entity.Question;
import com.atguigu.exam.exception.ExamException;
import com.atguigu.exam.mapper.ExamRecordMapper;
import com.atguigu.exam.mapper.PaperMapper;
import com.atguigu.exam.mapper.PaperQuestionMapper;
import com.atguigu.exam.mapper.QuestionMapper;
import com.atguigu.exam.service.PaperQuestionService;
import com.atguigu.exam.service.PaperService;
import com.atguigu.exam.vo.AiPaperVo;
import com.atguigu.exam.vo.PaperVo;
import com.atguigu.exam.vo.RuleVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 试卷服务实现类
 */
@Slf4j
@Service
@Transactional
public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> implements PaperService {

    @Autowired
    private PaperQuestionService paperQuestionService;
    @Autowired
    private PaperQuestionMapper paperQuestionMapper;
    @Autowired
    private ExamRecordMapper examRecordMapper;
    @Autowired
    private QuestionMapper questionMapper;

    @Override
    public Paper getDetailById(Integer id) {
        Paper paper = baseMapper.getDetailById(id);
        return paper;
    }

    @Override
    public void createPaper(PaperVo paperVo) {
        //判断创建的试卷是否已存在
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, paperVo.getName()));
        if (exists) {
            //表示存在重复的试卷,不能添加
            throw new ExamException(1001, "该试卷名已存在");
        }
        //创建Paper
        Paper paper = new Paper();
        //将PaperVo的属性赋值给Paper
        BeanUtils.copyProperties(paperVo, paper);
        //将paper的状态设置为DRAFT
        paper.setStatus("DRAFT");
        //获取所有的题目
        Map<Integer, BigDecimal> questions = paperVo.getQuestions();
        //设置试卷题目数量
        paper.setQuestionCount(questions.size());
        //设置试卷的总分
        BigDecimal totalScore = questions.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        paper.setTotalScore(totalScore);
        //插入试卷,并获取试卷的id,必须插入试卷后才能回显id
        baseMapper.insert(paper);
        List<PaperQuestion> paperQuestionList = questions.entrySet().stream().map(entry -> {
            PaperQuestion paperQuestion = new PaperQuestion(paper.getId(), Long.valueOf(entry.getKey().toString()), entry.getValue());
            return paperQuestion;
        }).collect(Collectors.toList());
        //进行批量添加题目
        paperQuestionService.saveBatch(paperQuestionList);
    }

    @Override
    public void updatePaper(Integer id, PaperVo paperVo) {
        //根据id获取paper
        Paper paper = baseMapper.selectById(id);
        //判断状态为PUBLISHED的不能修改
        if ("PUBLISHED".equals(paper.getStatus())) {
            //状态为PUBLISHED的不能修改
            throw new ExamException(1003, "试卷已发布不能修改");
        }
        //判断修改之后的试卷名是否存在
        boolean exists = baseMapper.exists(new LambdaQueryWrapper<Paper>().eq(Paper::getName, paperVo.getName()).ne(Paper::getId, id));
        if (exists) {
            //存在相同的试卷名,不能修改,抛异常
            throw new ExamException(1004, "该试卷已经存在");
        }
        //将PaperVo的属性值复制到paper中
        BeanUtils.copyProperties(paperVo, paper);
        //获取所有的题目
        Map<Integer, BigDecimal> questionsMap = paperVo.getQuestions();
        //给paper设置题目数量
        paper.setQuestionCount(questionsMap.size());
        //给paper设置题目总分
        paper.setTotalScore(questionsMap.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add));
        //修改试卷
        baseMapper.updateById(paper);
        //从试卷中删除所有的题目
        paperQuestionMapper.delete(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, id));
        //往表中插入元素
        //将questionsMap转换为List<Question>
        List<PaperQuestion> paperQuestionList = questionsMap.entrySet().stream().map(entry -> {
            PaperQuestion paperQuestion = new PaperQuestion(paper.getId(), Long.valueOf(entry.getKey().toString()), entry.getValue());
            return paperQuestion;
        }).collect(Collectors.toList());
        paperQuestionService.saveBatch(paperQuestionList);
    }

    @Override
    public void deletePaperById(Integer id) {
        //根据id获取paper
        Paper paper = baseMapper.selectById(id);
        //先判断状态为PUBLISHED的不能删除
        if ("PUBLISHED".equals(paper.getStatus())) {
            throw new ExamException(1005, "该试卷已经发布，不能修改");
        }
        //判断如果在考试记录表中存在也不能删除
        Long count = examRecordMapper.selectCount(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getExamId, id));
        if (count > 0) {
            throw new ExamException(1006, "该试卷有对应的考试记录，不能删除");
        }
        //删除试卷
        baseMapper.deleteById(id);
        //删除中间表的题目数据
        paperQuestionMapper.delete(new LambdaQueryWrapper<PaperQuestion>().eq(PaperQuestion::getPaperId, id));
    }

    @Override
    public void updatePaperStatus(Integer id, String status) {
        //判断是否有正在进行考试的
        Long count = examRecordMapper.selectCount(new LambdaQueryWrapper<ExamRecord>().eq(ExamRecord::getExamId, id).eq(ExamRecord::getStatus, "进行中"));
        if (count > 0) {
            //表示有正在及进行考试的试卷
            throw new ExamException(1007, "改试卷正在进行考试，不能修改状态");
        }
        baseMapper.update(null, new LambdaUpdateWrapper<Paper>().set(Paper::getStatus, status).eq(Paper::getId, id));

    }

    @Override
    public Paper createPaperWithAI(AiPaperVo aiPaperVo) {
        //创建Paper对象
        Paper paper = new Paper();
        //将AiPaperVo中的属性赋值给paper
        BeanUtils.copyProperties(aiPaperVo, paper);
        //给paper中的属性赋值
        paper.setStatus("DRAFT");
        //保存试卷
        baseMapper.insert(paper);
        //根据选题的规则选择题目以及得出总分
        //设置题目数量
        int questionCount = 0;
        //设置总分
        BigDecimal totalScore = BigDecimal.ZERO;
        for (RuleVo rule : aiPaperVo.getRules()) {
            //校验规则下的题目数量
            if (rule.getCount() == 0) {
                //该题目下不用出题
                log.warn("在：{}类型下，不需要出题！", rule.getType().name());
                continue;
            }
            //获取分类下的所有题目,不同分类号下所有类型的所有题目
            LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            questionLambdaQueryWrapper.eq(Question::getType, rule.getType().name());
            questionLambdaQueryWrapper.in(!CollectionUtils.isEmpty(rule.getCategoryIds()), Question::getCategoryId, rule.getCategoryIds());
            //调用方法查询所有题目
            List<Question> allQuestionList = questionMapper.selectList(questionLambdaQueryWrapper);
            //验空
            if (ObjectUtils.isEmpty(allQuestionList)) {
                log.warn("在：{}类型下，我们指定的分类：{},没有查询到题目信息！", rule.getType().name(), rule.getCategoryIds());
                continue;
            }
            //判断下是否有规则下count数量！ 没有要全部了
            int realNumbers = Math.min(rule.getCount(), allQuestionList.size());
            //步骤5：本次规则下添加的数量和分数累加
            questionCount += realNumbers;
            totalScore = totalScore.add(BigDecimal.valueOf((long) realNumbers * rule.getScore()));

            //先打乱数据，再截取需要题目数量
            Collections.shuffle(allQuestionList);
            List<Question> realQuestionList = allQuestionList.subList(0, realNumbers);

            //转成中间表并进行保存
            List<PaperQuestion> paperQuestionList = realQuestionList.stream().map(question -> {
                PaperQuestion paperQuestion = new PaperQuestion(paper.getId(), question.getId(), BigDecimal.valueOf(rule.getScore()));
                return paperQuestion;
            }).collect(Collectors.toList());
            paperQuestionService.saveBatch(paperQuestionList);
        }
        //修改试卷信息（总题数，总分数）
        paper.setTotalScore(totalScore);
        paper.setQuestionCount(questionCount);
        baseMapper.updateById(paper);
        return paper;
    }
}